﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using LitJson;

[AddComponentMenu("PUEX/EventHandle/EventHandle")]
public class PUEXEventHandle : PUEXHandle {

	public enum HandleType {
		HT_EMITTER_ENABLE,
		HT_EMITTER_DISABLE,
		HT_EMITTER_EMIT,
		HT_AFFECTOR_ENABLE,
		HT_AFFECTOR_DISABLE,
		HT_AFFECTOR_TRIGGER,
		HT_NOTIFY_EVENT,
		HT_DISPATCH_EVENT,
		HT_SPAWN_SUBSYSTEM,
	};
	
	#region - Editable property
	public HandleType handleType;
	public int intValue;
	public float floatValue;
	public string stringValue = "";
	#endregion
	
	#region - Lifecycle
	public PUEXEventHandle () 
	{
		handleType = HandleType.HT_EMITTER_ENABLE;
		intValue = 0;
		floatValue = 0f;
	}
	#endregion
	
	#region - Event
	public override void notifyEmitterStart ()
	{
		if (_enabled && eventType == PUEXHandle.EvnetType.ET_EMITTER_START) {
			handle (null, ownerEmitter);
		}
	}
	
	public override void notifyEmitterEnd ()
	{
		if (_enabled && eventType == PUEXHandle.EvnetType.ET_EMITTER_END) {
			handle (null, ownerEmitter);
		}
	}
	
	public override void notifyParticleEmission (PUEXParticle particle)
	{
		if (_enabled && eventType == PUEXHandle.EvnetType.ET_PARTICLE_EMISSION) {
			handle (particle, ownerEmitter);
		}
	}
	
	public override void notifyParticleExpiration (PUEXParticle particle)
	{
		if (_enabled && eventType == PUEXHandle.EvnetType.ET_PARTICLE_EXPIRATION) {
			handle (particle, ownerEmitter);
		}
	}
	
	public override void notifyParticleCollided (PUEXParticle particle)
	{
		if (_enabled && eventType == PUEXHandle.EvnetType.ET_PARTICLE_COLLIDED) {
			handle (particle, ownerEmitter);
		}
	}
	
	public override void notifyEvent (string eventName)
	{
		if (_enabled && eventType == PUEXHandle.EvnetType.ET_NOTIFY_EVENT && this.eventName == eventName) {
			handle (null, ownerEmitter);
		}
	}
	#endregion
	
	#region - Handle
	public void handle (PUEXParticle particle, PUEXEmitter emitter)
	{
		switch (handleType) {
		case HandleType.HT_EMITTER_ENABLE: {
			if (stringValue.Length > 0 && emitter != null && emitter.ownerParticleSystem != null) {
				for (int i = 0; i < emitter.ownerParticleSystem.emitters.Count; i++) {
					if (emitter.ownerParticleSystem.emitters[i].emitterName == stringValue) {
						emitter.ownerParticleSystem.emitters[i].enable();
						break;
					}
				}
			}
			
			break;
		}
		case HandleType.HT_EMITTER_DISABLE: {
			if (stringValue.Length > 0 && emitter != null && emitter.ownerParticleSystem != null) {
				for (int i = 0; i < emitter.ownerParticleSystem.emitters.Count; i++) {
					if (emitter.ownerParticleSystem.emitters[i].emitterName == stringValue) {
						emitter.ownerParticleSystem.emitters[i].disable();
						break;
					}
				}
			}
			
			break;
		}
		case HandleType.HT_EMITTER_EMIT: {
			if (stringValue.Length > 0 && intValue > 0 && emitter != null && emitter.ownerParticleSystem != null) {
				for (int i = 0; i < emitter.ownerParticleSystem.emitters.Count; i++) {
					if (emitter.ownerParticleSystem.emitters[i].emitterName == stringValue) {
						emitter.ownerParticleSystem.emitters[i].emitParticles(intValue);
						break;
					}
				}
			}
			
			break;
		}
		case HandleType.HT_AFFECTOR_ENABLE: {
			if (stringValue.Length > 0 && emitter != null) {
				for (int i = 0; i < emitter.affectors.Length; i++) {
					if (emitter.affectors[i].affectorName == stringValue) {
						emitter.affectors[i].enable ();
						break;
					}
				}
			}
			
			break;
		}
		case HandleType.HT_AFFECTOR_DISABLE: {
			if (stringValue.Length > 0 && emitter != null) {
				for (int i = 0; i < emitter.affectors.Length; i++) {
					if (emitter.affectors[i].affectorName == stringValue) {
						emitter.affectors[i].disable ();
						break;
					}
				}
			}
			
			break;
		}
		case HandleType.HT_AFFECTOR_TRIGGER: {
			if (floatValue > 0f && stringValue.Length > 0 && emitter != null) {
				for (int i = 0; i < emitter.affectors.Length; i++) {
					if (emitter.affectors[i].affectorName == stringValue) {
						emitter.affectors[i].trigger (floatValue);
						break;
					}
				}
			}
			
			break;
		}
		case HandleType.HT_NOTIFY_EVENT: {
			if (emitter != null && emitter.ownerParticleSystem != null && stringValue.Length > 0) {
				emitter.ownerParticleSystem.notifyEvent(stringValue);
			}
			
			break;
		}
		case HandleType.HT_DISPATCH_EVENT: {
			if (emitter != null && emitter.ownerParticleSystem != null && stringValue.Length > 0) {
				emitter.ownerParticleSystem.dispatchEvent(stringValue);
			}
			
			break;
		}
		case HandleType.HT_SPAWN_SUBSYSTEM: {
			if (particle != null && stringValue.Length > 0 && emitter != null && emitter.ownerParticleSystem != null && emitter.ownerParticleSystem.subParticleSystemTemplates.ContainsKey(stringValue)) {
				var subSystemTemplate = emitter.ownerParticleSystem.subParticleSystemTemplates[stringValue];
				if (subSystemTemplate.isSubParticleSystemTemplate) {
					// create sub system
					var subSystemInstance = GameObject.Instantiate(subSystemTemplate);
					
					if (particle.hasEventFlags(PUEXParticle.PEF_EXPIRED)) {
						subSystemInstance.destroyOnFinish = true;
					} else {
						subSystemInstance.ownerParticleSystem = emitter.ownerParticleSystem;
						particle.attachedSystem = subSystemInstance;
						subSystemInstance.destroyOnFinish = false;
					}
					
					// start sub particle system
					subSystemInstance.gameObject.SetActive(true);
					
					subSystemInstance.transform.parent = emitter.ownerParticleSystem.transform; //HEEK: ??? must after SetActive(true)
					
					// reset prefab transform
					subSystemInstance.transform.localPosition = Vector3.zero;
					subSystemInstance.transform.localRotation = Quaternion.identity;
					subSystemInstance.transform.localScale = Vector3.one;
					
					// add child to emitter
					if (emitter.keepLocal) {
						if (subSystemInstance.inheritOwnerTranslation)
							subSystemInstance.position = particle.position;
						if (subSystemInstance.inheritOwnerRotation)
							subSystemInstance.rotation = particle.orientation;
						if (subSystemInstance.inheritOwnerScale)
							subSystemInstance.scale = particle.dimensions();
					} else {
						Matrix4x4 systemInvMat = emitter.ownerParticleSystem.systemToWorldTransform.inverse;
						Matrix4x4 mat = systemInvMat * particle.transform();
						
						Vector3 s = Vector3.one;
						Quaternion r = Quaternion.identity;
						Vector3 p = Vector3.zero;
						PUEXUtils.matrixDecompose(mat, ref s, ref r, ref p);
						
						if (subSystemInstance.inheritOwnerTranslation)
							subSystemInstance.position = p;
						if (subSystemInstance.inheritOwnerRotation)
							subSystemInstance.rotation = r;
						if (subSystemInstance.inheritOwnerScale)
							subSystemInstance.scale = s;
					}
				}
			}
			
			break;
		}
		}
	}
	#endregion
	
	#region - Param property
	public override void updateParams (PUEXParticleSystem system)
	{
		base.updateParams (system);
	}
	#endregion
	
	#region - Serialization
	public override JsonData save (JsonData emitterData, JsonData systemData)
	{
		JsonData ret = base.save (emitterData, systemData);
		
		switch (handleType) {
		case HandleType.HT_EMITTER_ENABLE: {
			ret ["handle_type"] = "emitter_enable";
			ret ["string_value"] = stringValue;
			break;
		}
		case HandleType.HT_EMITTER_DISABLE: {
			ret ["handle_type"] = "emitter_disable";
			ret ["string_value"] = stringValue;
			break;
		}
		case HandleType.HT_EMITTER_EMIT: {
			ret ["handle_type"] = "emitter_emit";
			ret ["string_value"] = stringValue;
			ret ["int_value"] = intValue;
			break;
		}
		case HandleType.HT_AFFECTOR_ENABLE: {
			ret ["handle_type"] = "affector_enable";
			ret ["string_value"] = stringValue;
			break;
		}
		case HandleType.HT_AFFECTOR_DISABLE: {
			ret ["handle_type"] = "affector_disable";
			ret ["string_value"] = stringValue;
			break;
		}
		case HandleType.HT_AFFECTOR_TRIGGER: {
			ret ["handle_type"] = "affector_trigger";
			ret ["string_value"] = stringValue;
			ret ["float_value"] = floatValue;
			break;
		}
		case HandleType.HT_NOTIFY_EVENT: {
			ret ["handle_type"] = "notify_event";
			ret ["string_value"] = stringValue;
			break;
		}
		case HandleType.HT_DISPATCH_EVENT: {
			ret ["handle_type"] = "dispatch_event";
			ret ["string_value"] = stringValue;
			break;
		}
		case HandleType.HT_SPAWN_SUBSYSTEM: {
			ret ["handle_type"] = "spawn_subsystem";
			ret ["string_value"] = stringValue;
			break;
		}
		}
		
		return ret;
	}
	#endregion

}
